<template>
  <el-form :model="formData" ref="formRef" :rules="rules" label-width="80px">
    <template v-for="item in formItems" :key="item.prop">
      <el-form-item :label="item.label" :prop="item.prop" :title="`el-${item.type}`">
        <!-- <DicSelect
          v-if="item.type === 'dict-select'"
          v-model="formData[item.prop]"
          :code="item.config.code"
          :placeholder="item.placeholder"
        ></DicSelect> -->
        <!-- 上传 -->
        <el-upload
          ref="uploadRef"
          list-type="picture-card"
          v-if="item.type === 'upload'"
          :file-list="formData[item.prop]"
          :on-success="handleUploadSuccess"
          :on-error="handleUploadError"
          :on-remove="handleUploadRemove"
          :on-change="handleUploadChange"
          :on-preview="(file: UploadFile) => handlePreview(file, formData[item.prop]?.fileList)"
          v-bind="item.config"
        >
          <template #trigger>
            <slot :name="item.slot">
              <el-icon><Plus /></el-icon>
            </slot>
          </template>
          <template #tip>
            <div class="el-upload__tip">{{ item.placeholder }}</div>
          </template>
          <el-image-viewer
            v-if="dialogVisible"
            :url-list="urlList"
            :z-index="9999"
            :initial-index="currentIndex"
            @close="handlePreviewClose"
          ></el-image-viewer>
        </el-upload>
        <el-checkbox-group
          v-if="item.type === 'checkbox'"
          v-model="formData[item.prop]"
          v-bind="item.config"
        >
          <el-checkbox
            v-for="(option, index) in item.options"
            :key="index"
            :label="option.label"
            :value="option.value"
          >
            {{ option.label }}
          </el-checkbox>
        </el-checkbox-group>
        <el-radio-group
          v-if="item.type === 'radio'"
          v-model="formData[item.prop]"
          v-bind="item.config"
        >
          <el-radio v-for="(option, index) in item.options" :key="index" :label="option.value">
            {{ option.label }}
          </el-radio>
        </el-radio-group>
        <el-select
          v-else-if="item.type === 'select'"
          v-model="formData[item.prop]"
          v-bind="item.config"
        >
          <el-option
            v-for="option in item.options"
            :key="option.value"
            :label="option.label"
            :value="option.value"
          ></el-option>
        </el-select>
        <!-- <MdEditor
          v-else-if="item.type === 'md-editor'"
          v-model="formData[item.prop]"
          v-bind="item.config"
        /> -->
        <component
          v-else
          :is="getComponent(item.type)"
          v-model="formData[item.prop]"
          :theme="useThemeStore().isDark ? 'dark' : 'light'"
          v-bind="item.config"
        ></component>
      </el-form-item>
    </template>
    <template v-if="showAction">
      <el-form-item>
        <el-button type="primary" @click="handleSubmit">提交</el-button>
        <el-button @click="handleReset(formRef)">重置</el-button>
      </el-form-item>
    </template>
    <el-form-item>
      <slot name="footer" :form="formRef"></slot>
    </el-form-item>
  </el-form>
</template>
<script setup lang="ts">
  import { MdEditor } from 'md-editor-v3'
  import 'md-editor-v3/lib/style.css'
  import { ElInput } from 'element-plus'
  import type {
    FormInstance,
    UploadProps,
    UploadFile,
    UploadInstance,
    UploadFiles
  } from 'element-plus'
  import type { IFormItem } from './type'
  import DicSelect from '../Dictionary/DicSelect.vue'
  import { useThemeStore } from '@/stores/themeStore'
  const props = defineProps({
    formItems: {
      type: Array as PropType<IFormItem[]>,
      default: () => []
    },
    showAction: {
      type: Boolean,
      default: true
    },
    formData: {
      type: Object as PropType<Record<string, any>>,
      default: () => ({})
    }
  })

  const emit = defineEmits(['submit'])
  const urlList = ref([])
  const currentIndex = ref(0)
  const dialogVisible = ref(false)
  const formRef = ref<FormInstance>()
  const uploadRef = ref<UploadInstance>()
  const rules = ref<Record<string, any>>({})
  const formData = ref<Record<string, any>>({ ...props.formData })
  console.log('formData1', formData)
  const getComponent = (type: string) => {
    return {
      input: ElInput,
      select: ElSelect,
      'dict-select': DicSelect,
      'md-editor': MdEditor,
      upload: ElUpload
    }[type]
  }
  // 监听表单数据源变化 赋值给formData和rules
  // 使用computed会报错 因为computed会缓存数据 所以使用watchEffect
  // watchEffect和watch区别 1.watchEffect会自动执行 2.watchEffect会自动监听依赖项 3.watchEffect会自动取消监听 4.watchEffect会自动执行一次
  /**
   * watchEffect 的优点：
      自动追踪依赖：
        自动收集依赖，不需要显式指定要监听的数据
        代码更简洁
      立即执行：
        创建时会立即执行一次
        适合需要立即初始化的场景
    watch 的优点：
      更明确的依赖关系：
        明确知道在监听什么数据
        代码可维护性更好
      可以访问新值和旧值：
        能够比较变化前后的值
        可以根据变化做更精确的控制
   */
  watchEffect(() => {
    props.formItems.forEach((item: IFormItem) => {
      rules.value[item.prop] = item.rules
    })
  })
  watch(
    () => props.formData,
    (newVal: Record<string, any>) => {
      formData.value = { ...newVal }
      console.log('formData2', formData)
    },
    { immediate: true, deep: true }
  )
  const validate = async () => {
    return await formRef.value?.validate()
  }

  const handleReset = async (formEl: FormInstance) => {
    const form = formEl || formRef.value
    form.resetFields()
  }
  const handleSubmit = async () => {
    await validate()
      .then(_res => {
        emit('submit', formData.value)
      })
      .catch(err => {
        console.log('form-handlesubmit-err', err)
      })
  }
  const handlePreview: UploadProps['onPreview'] = (
    uploadFile: UploadFile,
    fileList: UploadFiles
  ) => {
    console.log('handlePreview', uploadFile, 1, fileList, uploadRef.value)
    // dialogImageUrl.value = uploadFile.url!
    urlList.value = fileList.map((item, index) => {
      if (item.url === uploadFile.url) {
        currentIndex.value = index
      }
      return item.url!
    })
    dialogVisible.value = uploadFile
  }
  const handlePreviewClose = () => {
    console.log('handlePreviewClose')
    dialogVisible.value = false
  }
  const handleUploadError: UploadProps['onError'] = (
    error: Error,
    uploadFile: UploadFile,
    fileList: UploadFile[]
  ) => {
    console.log('handleError', error, uploadFile, fileList)
  }

  const handleUploadRemove: UploadProps['onRemove'] = (
    uploadFile: UploadFile,
    fileList: UploadFile[]
  ) => {
    console.log('handleRemove', uploadFile, fileList)
  }

  const handleUploadSuccess: UploadProps['onSuccess'] = (
    response: any,
    uploadFile: UploadFile,
    fileList: UploadFiles
  ) => {
    const uploadItem = props.formItems.find((item: IFormItem) => item.type === 'upload')
    formData.value[uploadItem?.prop] = { response, file: uploadFile, fileList }
    console.log('handleSuccess', uploadFile, fileList)
  }
  const handleUploadChange: UploadProps['onChange'] = (
    uploadFile: UploadFile,
    fileList: UploadFile[]
  ) => {
    const uploadItem = props.formItems.find((item: IFormItem) => item.type === 'upload')
    formData.value[uploadItem?.prop] = { file: uploadFile, fileList }
    console.log('handleChange', uploadFile, fileList)
  }

  defineExpose({
    validate,
    handleReset,
    formData
  })
</script>
<style lang="scss" scoped></style>
